#include <QAction>
#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QShortcut>
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QStatusBar>
#include <QMetaObject>
#include <QInputDialog>
#include <QSettings>
#include <QDir>
#include <QSound>
#include <QPushButton>
#include <QProcess>
#include <QDialog>
#include <QVBoxLayout>
#include <QDockWidget>
#include <QDebug>
#include <QyLexerFactory>
#include <QyEditorBase>
#include <QySciEdit>
#include <QySciLexer>
#include <QyScript>
// #include <Qsci/qscilexercpp.h>
// #include <Qsci/qscilexerproperties.h>

#include "QyLambdaEditor.h"
#include "QyConfigurator.h"
#include "QySourceNavigator.h"

#define CREATEACTION( name, title, key ) QAction * name = createAction( this, #name, title, key )
#define CONNECTACTION( name, obj, slot ) connect( name, SIGNAL( triggered() ), obj, slot )

/**************************************************************************************************/

inline QAction * createAction( QObject * parent, const QString & name, const QString & title,
	const QString & key )
{

	QAction * action = new QAction( title, parent );

	action->setObjectName(name);
	action->setShortcut( QKeySequence(key) );

	return action;
}

inline QString settingsPath() {

	return QDir::homePath() + "/.lambdaeditor";
}

inline QStringList fileForOpen() {

	QStringList args( qApp->arguments() ), files;

	args.takeFirst();

	foreach ( QString arg, args ) {

		QFileInfo info(arg);

		if ( info.exists() )
			files.append( info.absoluteFilePath() );

	}

	return files;
}

/**************************************************************************************************/

QyMPlayer::QyMPlayer( const QString & fileName, QObject * parent ) : QObject(parent) {

	p_fileName = fileName;

}

void QyMPlayer::play() {

	QProcess::startDetached( "/usr/bin/mplayer", QStringList() << "-really-quiet" << p_fileName );

}

/**************************************************************************************************/

QyLambdaEditor::QyLambdaEditor() : QMainWindow() {

	configurator = new QyConfigurator(this);

	createUi();
	createMenu();

	QMetaObject::connectSlotsByName(this);
	connect( configurator, SIGNAL( restoreSession(const QString&) ),
		editorBase, SLOT( loadSession(const QString&) ) );
	connect( configurator, SIGNAL( saveSession(const QString&) ),
		editorBase, SLOT( saveSession(const QString&) ) );
	connect( configurator, SIGNAL( initScriptComplete() ),
		editorBase, SLOT( updateConfig() ) );
	connect( configurator, SIGNAL( loadPlugins(const QString&) ),
		sourceNavigator, SLOT( loadPluginsFrom(const QString&) ) );
	connect( sourceNavigator, SIGNAL( fileOpend(const QString&) ),
		editorBase, SLOT( openFile(const QString&) ) );
	connect( sourceNavigator, SIGNAL( fileOpendOnLine(const QString&,int) ),
		editorBase, SLOT( openFileOnLine(const QString&,int) ) );

	setWindowTitle( tr("lambdapro") );

}

QyLambdaEditor::~QyLambdaEditor() {

	configurator->saveSettings();

}

void QyLambdaEditor::restoreSettings() {

	configurator->restoreSettings();

	QStringList files( fileForOpen() );

	if ( files.count() ) {

		editorBase->clear();

		foreach ( QString fileName, files )
			editorBase->openFile(fileName);

	}

}

void QyLambdaEditor::on_newSectionAction_triggered() {

	QString name = QInputDialog::getText( this, tr("New section"), tr("Name") );

	if ( name.isEmpty() )
		return;

	editorBase->openEmpty(name);

}

void QyLambdaEditor::on_readSettingsAction_triggered() {

	configurator->runInitScript();

}

void QyLambdaEditor::on_tambourineAction_triggered() {

	static QDialog * tambourineDialog = 0;

	if (!tambourineDialog) {

		tambourineDialog = new QDialog(this);
		QVBoxLayout * layout = new QVBoxLayout(tambourineDialog);
		QPushButton * tambourineButton = new QPushButton(tambourineDialog);

		tambourineDialog->setWindowTitle( tr("Tambourine") );
		layout->addWidget(tambourineButton);
		tambourineButton->setIconSize( QSize( 250, 250 ) );
		tambourineButton->setIcon( QIcon(":/images/tambourine.png") );

// 		qDebug() << "sound path" << configurator->path() + "/tambourine.wav";

		QObject * tambourineSound = 0;

		if ( QSound::isAvailable() )
			tambourineSound = new QSound( configurator->path() + "/tambourine.wav", this );
		else
			tambourineSound = new QyMPlayer( configurator->path() + "/tambourine.wav", this );

		connect( tambourineButton, SIGNAL( clicked() ),
			tambourineSound, SLOT( play() ) );

	}

	tambourineDialog->show();

}

void QyLambdaEditor::on_toggleSnAction_triggered( bool checked ) {

	sourceNavigatorDock->setVisible(checked);

	if (checked)
		sourceNavigatorDock->setFocus();

}

void QyLambdaEditor::on_toggleSnSocusAction_triggered() {

// 	qDebug() << "sourceNavigatorDock->isVisible()" << sourceNavigatorDock->isVisible();

	QySciEdit * edit = editorBase->currentEdit();

	if ( sourceNavigatorDock->isVisible() && edit ) {

// 		qDebug() << "sourceNavigatorDock->focusWidget()" << sourceNavigatorDock->focusWidget();

		if ( edit->hasFocus() )
			sourceNavigatorDock->setFocus();
		else
			edit->setFocus();


	} else {

// 		qDebug() << "sourceNavigatorDock->setFocus()";

		sourceNavigatorDock->setVisible(true);
		sourceNavigatorDock->setFocus();

	}

}

void QyLambdaEditor::createUi() {

	QLabel * editorStatus = new QLabel(this);
	sourceNavigatorDock = new QDockWidget( tr("Source navigator"), this );
	editorBase = new QyEditorBase(this);
	sourceNavigator = new QySourceNavigator(sourceNavigatorDock);

	sourceNavigatorDock->setObjectName("sourceNavigatorDock");
	sourceNavigatorDock->setWidget(sourceNavigator);
	sourceNavigatorDock->setFocusProxy(sourceNavigator);
	setCentralWidget(editorBase);
	statusBar()->addWidget(editorStatus);
	addDockWidget( Qt::RightDockWidgetArea, sourceNavigatorDock );

	QObject::connect( editorBase, SIGNAL( statusChanged(const QString&) ),
		editorStatus, SLOT( setText(const QString&) ) );

}

void QyLambdaEditor::createMenu() {

	// creating

	// file
	CREATEACTION( newTabAction, tr("New"), "Ctrl+N" );
	CREATEACTION( openAction, tr("Open"), "Ctrl+O" );
	CREATEACTION( saveAction, tr("save"), "Ctrl+S" );
	CREATEACTION( saveAsAction, tr("Save as ..."), "Ctrl+Shift+S" );
	CREATEACTION( loadSessionAction, tr("Load session ..."), "" );
	CREATEACTION( saveSessionAction, tr("Save session ..."), "" );
	CREATEACTION( quitAction, tr("Quit"), "Alt+F4" );

	// edit
	CREATEACTION( newSectionAction, tr("New section"), "Ctrl+Shift+T" );
	CREATEACTION( closeCurrentAction, tr("Close current"), "Ctrl+W" );
	CREATEACTION( closeCurrentSectionAction, tr("Close current section"), "Ctrl+Shift+W" );
	CREATEACTION( closeAllAction, tr("Close all"), "Ctrl+Shift+Alt+W" );
	CREATEACTION( changeEncodingAction, tr("Change encoding"), "Ctrl+Alt+E" );
	CREATEACTION( readSettingsAction, tr("Read settings"), "Ctrl+Alt+R" );
	CREATEACTION( switchCurrentAction, tr("Switch current file"), "Ctrl+Alt+C" );
	CREATEACTION( toggleCurrentCommentAction, tr("Toggle current line comment"), "Ctrl+Q" );
	// CREATEACTION( duplicateCurrentAction, tr("Duplicate current [Ctrl+D]"), "" );
	// CREATEACTION( makeSelectionUppercaseAction, tr("Make selection uppercase [Ctrl+Shift+U]"), "" );
	// CREATEACTION( makeSelectionLowercaseAction, tr("Make selection lowercase [Ctrl+U]"), "" );
	// CREATEACTION( swapLinesAction, tr("Swap current and up lines [Ctrl+T]"), "" );

	// search
	CREATEACTION( findAction, tr("Find ..."), "Ctrl+F" );
	CREATEACTION( findNextAction, tr("Find next"), "F3" );
	CREATEACTION( replaceAction, tr("Replace ..."), "Ctrl+H" );
	CREATEACTION( toggleBookmarkAction, tr("Toggle bookmark"), "Ctrl+F2" );
	CREATEACTION( nextBookmarkAction, tr("Next bookmark"), "F2" );
	CREATEACTION( gotoAction, tr("Goto ..."), "Ctrl+G" );

	// view
	CREATEACTION( toggleCurrentFoldAction, tr("Toggle current fold"), "Ctrl+*" );
	CREATEACTION( toggleAllFoldAction, tr("Toggle all fold"), "Ctrl+Alt+Z" );
	CREATEACTION( toggleSnAction, tr("Toggle source navigator"), "F5" );
	CREATEACTION( toggleSnSocusAction, tr("Toggle source navigator focus"), "F8" );

	// help
	CREATEACTION( tambourineAction, tr("Tambourine"), "" );

	{// connecting
	// file
	CONNECTACTION( newTabAction, editorBase, SLOT( openEmpty() ) );
	CONNECTACTION( openAction, editorBase, SLOT( openFile() ) );
	CONNECTACTION( saveAction, editorBase, SLOT( saveCurrent() ) );
	CONNECTACTION( saveAsAction, editorBase, SLOT( saveCurrentAs() ) );
	CONNECTACTION( loadSessionAction, editorBase, SLOT( loadSession() ) );
	CONNECTACTION( saveSessionAction, editorBase, SLOT( saveSession() ) );
	CONNECTACTION( quitAction, qApp, SLOT( quit() ) );

	// edit
	CONNECTACTION( closeCurrentAction, editorBase, SLOT( closeCurrent() ) );
	CONNECTACTION( closeCurrentSectionAction, editorBase, SLOT( closeCurrentSection() ) );
	CONNECTACTION( closeAllAction, editorBase, SLOT( clear() ) );
	CONNECTACTION( changeEncodingAction, editorBase, SLOT( reopenCurrentWithCodec() ) );
	CONNECTACTION( switchCurrentAction, editorBase, SLOT( switchCurrentFile() ) );
	CONNECTACTION( toggleCurrentCommentAction, editorBase, SLOT( toggleCurrentComment() ) );

	// search
	CONNECTACTION( findAction, editorBase, SLOT( findText() ) );
	CONNECTACTION( findNextAction, editorBase, SLOT( findTextNext() ) );
	CONNECTACTION( replaceAction, editorBase, SLOT( replaceText() ) );
	CONNECTACTION( toggleBookmarkAction, editorBase, SLOT( toggleBookmark() ) );
	CONNECTACTION( nextBookmarkAction, editorBase, SLOT( findNextBookmark() ) );
	CONNECTACTION( gotoAction, editorBase, SLOT( gotoLine() ) );

	// view
	CONNECTACTION( toggleCurrentFoldAction, editorBase, SLOT( toggleCurrentFoldCurrent() ) );
	CONNECTACTION( toggleAllFoldAction, editorBase, SLOT( toggleCurrentFoldAll() ) );
	}

	{// customizing
	toggleSnAction->setCheckable(true);
	toggleSnAction->setChecked( sourceNavigatorDock->isVisible() );
	connect( sourceNavigatorDock, SIGNAL( visibilityChanged(bool) ),
		toggleSnAction, SLOT( setChecked(bool) ) );
	}

	{// menus
	QMenu * fileMenu = menuBar()->addMenu( tr("&File") );

	fileMenu->addAction(newTabAction);
	fileMenu->addAction(openAction);
	fileMenu->addAction(saveAction);
	fileMenu->addAction(saveAsAction);
	fileMenu->addSeparator();
	fileMenu->addAction(loadSessionAction);
	fileMenu->addAction(saveSessionAction);
	fileMenu->addSeparator();
	fileMenu->addAction(quitAction);

	QMenu * editMenu = menuBar()->addMenu( tr("&Edit") );

	editMenu->addAction(newSectionAction);
	editMenu->addAction(closeCurrentAction);
	editMenu->addAction(closeCurrentSectionAction);
	editMenu->addAction(closeAllAction);
	editMenu->addSeparator();
	editMenu->addAction(changeEncodingAction);
	editMenu->addSeparator();
	editMenu->addAction(readSettingsAction);
	editMenu->addSeparator();
	editMenu->addAction(switchCurrentAction);
	editMenu->addSeparator();
	editMenu->addAction(toggleCurrentCommentAction);
	// editMenu->addAction(duplicateCurrentAction);
	// editMenu->addAction(makeSelectionUppercaseAction);
	// editMenu->addAction(makeSelectionLowercaseAction);
	// editMenu->addAction(swapLinesAction);

	QMenu * searchMenu = menuBar()->addMenu( tr("&Search") );

	searchMenu->addAction(findAction);
	searchMenu->addAction(findNextAction);
	searchMenu->addAction(replaceAction);
	searchMenu->addSeparator();
	searchMenu->addAction(toggleBookmarkAction);
	searchMenu->addAction(nextBookmarkAction);
	searchMenu->addSeparator();
	searchMenu->addAction(gotoAction);

	QMenu * viewMenu = menuBar()->addMenu( tr("&View") );

	viewMenu->addAction(toggleCurrentFoldAction);
	viewMenu->addAction(toggleAllFoldAction);
	viewMenu->addSeparator();
	viewMenu->addAction(toggleSnAction);
	viewMenu->addAction(toggleSnSocusAction);

	QMenu * helpMenu = menuBar()->addMenu( tr("&Help") );
	helpMenu->addAction(tambourineAction);
	}

}

/**************************************************************************************************/

int main( int argc, char ** argv ) {

	QApplication app( argc, argv );
	QApplication::setApplicationName("lambdapro");
	QApplication::setWindowIcon( QIcon(":/images/logo.png") );

	QyLambdaEditor w;

	w.restoreSettings();

	return app.exec();
}
